import requests
from flask import jsonify
import time
import threading
import uuid
from datetime import datetime
import random
import os
from urllib.parse import urlparse, urlencode, urlunparse, parse_qs
from moviepy.editor import *
import subprocess
import shutil

# testDir="D:\\project\\python\\py_videomaker\\videomaker\\demo\\input\\"
# hw_option="-hwaccel cuvid"
hw_option=""
# encoder_type="-c:v h264_nvenc -b:v 10M"
encoder_type="-codec:v libx264"
# --------------基础方法---------------------------------------------------------------
def mkdir(directory_path):
    # 如果目录不存在，则创建目录
    if not os.path.exists(directory_path):
        os.mkdir(directory_path)
        print(f"Directory '{directory_path}' has been created.")
    else:
        print(f"Directory '{directory_path}' already exists.")

def delete_dir(directory_path):
    # 删除目录及其内容
    if os.path.exists(directory_path):
        try:
            shutil.rmtree(directory_path)
            print(f"Directory '{directory_path}' and its contents have been deleted.")
        except Exception as e:
            print(f"Error deleting directory: {e}")
    else:
        print(f"Directory '{directory_path}' does not exist.")
            
def delete_file(file_path):
    # 检查文件是否存在
    if os.path.exists(file_path):
        try:
            os.remove(file_path)
            print(f"File '{file_path}' has been deleted.")
        except Exception as e:
            print(f"Error deleting file: {e}")
    else:
        print(f"File '{file_path}' does not exist.")

def file_exist(file_path):
    if os.path.exists(file_path):
        print("文件存在")
        return True
    else:
        print("文件不存在")  
        return False      
# 生成uuid
def uuid_str():
    # 生成一个随机的UUID（版本4）
    generated_uuid = uuid.uuid4()  
    # 将UUID对象转换为字符串
    uuid_string = str(generated_uuid)
    return uuid_string

# 执行命令行命令
def run_command(command):
    # 创建子进程并执行命令
    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    # 获取子进程的标准输出和标准错误输出
    output, error = process.communicate()
    # 打印输出结果
    msg=""
    if output:
        msg=output.decode('utf-8')
        print(msg)
    if error:
        msg=error.decode('utf-8')
        print(msg)
        # 等待子进程结束
    return msg

# print("开始")
# # 示例：执行一个命令行命令
# command = "ffmpeg -version"
# run_command(command)
# print("结束")
        
# wav转mp3
def ffmpeg_wav_to_mp3(wav_path,mp3_path,volume=12):
    if file_exist(wav_path)==False:
        print(f"WAV[{wav_path}]转换MP3[{mp3_path}]失败,源文件不存在")
        return False
    command = f"ffmpeg -i \"{wav_path}\" -af \"volume={volume}dB\" -codec:a libmp3lame -y \"{mp3_path}\""
    print(f"WAV[{wav_path}]转换MP3[{mp3_path}]:{command}")
    run_command(command)
    print(f"WAV[{wav_path}]转换MP3[{mp3_path}]完成.")
    return True


# wav_path=f"{testDir}voice.wav"
# mp3_path=f"{testDir}voice333.mp3"
# ffmpeg_wav_to_mp3(wav_path,mp3_path)

# mp4素材处理
def ffmpeg_mp4_sub(video_path,output_mp4_path,start_time_str="00:00:00",length_str="00:00:03"):
    command = f"ffmpeg {hw_option}  -i \"{video_path}\" -ss {start_time_str} -t {length_str} {encoder_type} -y \"{output_mp4_path}\""
    print(f"MP4素材[{video_path}]处理:{command}")
    run_command(command)
    print(f"MP4素材[{video_path}]处理完成.")

# mp4素材处理
def ffmpeg_mp4_scale_and_sub(video_path,output_mp4_path,start_time_str="00:00:00",length_str="00:00:03",width=720,height=1280,with_voice=True):
    no_voice_param="-an"
    if with_voice:
        no_voice_param=""
    # command = f"ffmpeg -i \"{video_path}\" -ss {start_time_str} -t {length_str} -vf \"scale={width}:{height}\" -c:v h264_nvenc -crf 23  {no_voice_param} -y \"{output_mp4_path}\""
    command = f"ffmpeg {hw_option} -i \"{video_path}\" -ss {start_time_str} -t {length_str} -vf \"scale={width}:{height}\" {encoder_type} {no_voice_param} -y \"{output_mp4_path}\""
    print(f"MP4素材[{video_path}]处理:{command}")
    run_command(command)
    print(f"MP4素材[{video_path}]处理完成.")

# video_path=f"{testDir}input.mp4"
# output_mp4_path=f"{testDir}o3.mp4"
# ffmpeg_mp4_scale_and_sub(video_path,output_mp4_path,"00:01:00","00:00:10",1080,1920)


# mp3素材处理
def ffmpeg_mp3_sub(mp3_path,output_mp3_path,tmpDir,start_time_str="00:00:00",length_str="00:00:03",output_start_sec=5):
    silence_path=""
    if output_start_sec>0:
        # 第N秒播放
        silence_path=f"{tmpDir}silence_{output_start_sec}.mp3"
        command = f"ffmpeg {hw_option} -f lavfi -i \"anullsrc=channel_layout=stereo:sample_rate=44100:duration={output_start_sec}\" -y \"{silence_path}\""
        print(f"MP3素材[{mp3_path}]处理（生成静音片段）:{command}")
        run_command(command)
        print(f"MP3素材[{mp3_path}]处理（生成静音片段）完成.")

        uuidStr = uuid_str()
        tmp_mp3_path=f"{tmpDir}tmp_{uuidStr}_{output_start_sec}.mp3"

        command = f"ffmpeg {hw_option} -i \"{mp3_path}\" -ss {start_time_str} -t {length_str} -c copy -y \"{tmp_mp3_path}\""
        print(f"MP3素材[{mp3_path}]处理(截取):{command}")
        run_command(command)
        print(f"MP3素材[{mp3_path}]处理(截取)完成.")


        # 写入合并文件txt
        audioLines = [
            f"file '{silence_path}'",
            f"file '{tmp_mp3_path}'  "
        ]
        uuidStr = uuid_str()
        audio_conat_txt_path = f"{tmpDir}{uuidStr}.txt"

        with open(audio_conat_txt_path, 'w' , encoding='utf-8') as file:
            for line in audioLines:
                file.write(line + '\n')

        # 合并音频        
        command = f"ffmpeg {hw_option} -f concat -safe 0 -i \"{audio_conat_txt_path}\"  -y \"{output_mp3_path}\""
        print(f"MP3素材[{mp3_path}]处理(合并):{command}")
        run_command(command)
        print(f"MP3素材[{mp3_path}]处理(合并)完成.")

        # 删除临时音频
        delete_file(silence_path)
        delete_file(audio_conat_txt_path)
    else:     
        # 没有前置时间
        command = f"ffmpeg {hw_option} -i \"{mp3_path}\" -ss {start_time_str} -t {length_str} -c copy -y \"{output_mp3_path}\""
        print(f"MP3素材[{mp3_path}]处理:{command}")
        run_command(command)
        print(f"MP3素材[{mp3_path}]处理完成.")


# mp3_path=f"{testDir}music.mp3"
# output_mp3_path=f"{testDir}o3.mp3"
# ffmpeg_mp3_sub(mp3_path,output_mp3_path,testDir,"00:00:16","00:00:10",5)

# MP3合并
def ffmpeg_mp3_concat(output_mp3_path,tmpDir,clip_path_array=[]):
        if len(clip_path_array)==0:
            return False
        # 写入合并文件txt
        audioLines = []
        for clip_path in clip_path_array:
            if file_exist(clip_path)==True:
                audioLines.append(f"file '{clip_path}'")
        if len(audioLines)==0:
            return False        
        uuidStr = uuid_str()
        audio_conat_txt_path = f"{tmpDir}{uuidStr}.txt"

        with open(audio_conat_txt_path, 'w' , encoding='utf-8') as file:
            for line in audioLines:
                file.write(line + '\n')

        # 合并音频        
        command = f"ffmpeg {hw_option} -f concat -safe 0 -i \"{audio_conat_txt_path}\"  -y \"{output_mp3_path}\""
        print(f"MP3素材[{output_mp3_path}]处理(合并):{command}")
        run_command(command)
        print(f"MP3素材[{output_mp3_path}]处理(合并)完成.")

        # 删除临时文件
        delete_file(audio_conat_txt_path)
        return True


# MP4合并
def ffmpeg_mp4_concat(output_mp4_path,tmpDir,clip_path_array=[],brate=10):
    # 生成合并txt
    videoLines = []
    for clip_path in clip_path_array:
        videoLines.append(f"file '{clip_path}'")
    
    uuidStr = uuid_str()
    video_conat_txt_path = f"{tmpDir}{uuidStr}.txt"

    with open(video_conat_txt_path, 'w' , encoding='utf-8') as file:
            for line in videoLines:
                file.write(line + '\n')   

    # command = f"ffmpeg -hwaccel cuvid -c:v h264_cuvid -f concat -safe 0 -i \"{video_conat_txt_path}\" -c:v h264_nvenc -b:v {brate}M -preset fast -y \"{output_mp4_path}\""
    command = f"ffmpeg {hw_option}  -f concat -safe 0 -i \"{video_conat_txt_path}\" -b:v {brate}M -preset fast {encoder_type} -y \"{output_mp4_path}\""
    print(f"MP4素材[{output_mp4_path}]处理合并:{command}")
    run_command(command)
    print(f"MP4素材[{output_mp4_path}]处理合并完成.")

    # 删除临时文件
    delete_file(video_conat_txt_path)

# mp4_path_array=[f"{testDir}output.mp4",f"{testDir}output_2.mp4"]
# output_mp4_path=f"{testDir}o4.mp4"
# ffmpeg_mp4_concat(output_mp4_path,testDir,mp4_path_array,20)


# MP4添加字幕(字幕路径只能是当前工作目录)
def ffmpeg_mp4_add_subtitles(source_mp4_path,output_mp4_path,srt_path_in_workdir):
    command = f"ffmpeg {hw_option}  -i \"{source_mp4_path}\" -vf \"subtitles={srt_path_in_workdir}\" {encoder_type} -codec:a copy -y \"{output_mp4_path}\""
    print(f"MP4素材[{output_mp4_path}]处理字幕:{command}")
    run_command(command)
    print(f"MP4素材[{output_mp4_path}]处理字幕完成.")

# source_mp4_path=f"{testDir}o3.mp4"
# output_mp4_path=f"{testDir}o5.mp4"
# srt_path=f"input.srt"
# ffmpeg_mp4_add_subtitles(source_mp4_path,output_mp4_path,srt_path)
    
# MP4添加音频
def ffmpeg_mp4_add_audio(source_mp4_path,output_mp4_path,audio_mp3_path):
    command = f"ffmpeg {hw_option}  -i \"{source_mp4_path}\" -i \"{audio_mp3_path}\" -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 -shortest -y \"{output_mp4_path}\""
    print(f"MP4素材[{output_mp4_path}]处理添加音频:{command}")
    run_command(command)
    print(f"MP4素材[{output_mp4_path}]处理添加音频完成.")

# source_mp4_path=f"{testDir}o5.mp4"
# output_mp4_path=f"{testDir}o6.mp4"
# audio_mp3_path=f"{testDir}o3.mp3"
# ffmpeg_mp4_add_audio(source_mp4_path,output_mp4_path,audio_mp3_path)
    
# MP4添加图标
def ffmpeg_mp4_add_icon(source_mp4_path,output_mp4_path,image_path,w=50,h=50,left=10,top=10):
    command = f"ffmpeg {hw_option}  -i \"{source_mp4_path}\" -i \"{image_path}\" -filter_complex \"[1:v]select='eq(n\,0)',scale={w}:{h}[logo];[0:v][logo]overlay={left}:{top}\" {encoder_type} -y \"{output_mp4_path}\""
    print(f"MP4素材[{output_mp4_path}]处理添加图标:{command}")
    run_command(command)
    print(f"MP4素材[{output_mp4_path}]处理添加图标完成.")

# source_mp4_path=f"{testDir}o6.mp4"
# output_mp4_path=f"{testDir}o7.mp4"
# image_path=f"{testDir}11.gif"
# ffmpeg_mp4_add_icon(source_mp4_path,output_mp4_path,image_path)

# 获取视频长度
def get_video_length(file_path):
    # source_video_clip = VideoFileClip(file_path)
    # duration = source_video_clip.duration
    # source_video_clip.close()
    # return f"{duration}" 
    file_path_str=f"{file_path}"
    file_path_str=file_path_str.replace("\\","/")
    file_path_str=file_path_str.replace("//","/")
    command = f"ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 \"{file_path_str}\""
    print(f"{file_path}获取视频长度:{command}")
    duration=run_command(command)
    print(f"{file_path}获取视频长度完成:{duration}")
    return duration
# ----------------------------------------------------------生成逻辑---------------------------------------------    
def get_time_str():
    # 获取当前日期和时间
    current_datetime = datetime.now()
    # 格式化日期和时间为字符串
    formatted_datetime = current_datetime.strftime("%Y%m%d%H%M%S")
    return formatted_datetime

def encode_url_after_questionmark(url):
    """
    对URL中的查询参数进行URL编码。
    
    :param url: 包含查询参数的URL字符串。
    :return: 查询参数URL编码后的新URL字符串。
    """
    parsed_url = urlparse(url)
    query_params = parse_qs(parsed_url.query)
    encoded_query_params = urlencode(query_params, doseq=True)
    new_url = urlunparse((
        parsed_url.scheme,
        parsed_url.netloc,
        parsed_url.path,
        parsed_url.params,
        encoded_query_params,
        parsed_url.fragment
    ))
    return new_url

def send_post_progress(progress_url, data):
    # 发送 POST 请求到 callbackUrl
    print(f"进度通知: {progress_url}...")
    progress_url = encode_url_after_questionmark(progress_url)
    response = requests.post(progress_url, json=data)
    if response.status_code != 200:
        print(f"进度通知失败: {progress_url}:{response.json()}")
        return jsonify({"error": "进度通知失败: "+progress_url+":"+response.json()}), 500
def send_post(callback_url, data):
    # 发送 POST 请求到 callbackUrl
    print(f"回调: {callback_url}...")
    callback_url = encode_url_after_questionmark(callback_url)
    print(f"回调(编码后): {callback_url}...")
    response = requests.post(callback_url, json=data)
    if response.status_code != 200:
        print(f"回调失败: {callback_url}:{response.json()}")
        return jsonify({"error": "回调失败: "+callback_url+":"+response.json()}), 500

# 格式化时间
def format_seconds(seconds):
    hours, remainder = divmod(seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return "{:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)


def _cal_duration(start_time,end_time):
    start_time = time_to_int(start_time)
    end_time = time_to_int(end_time)

    text_duration = end_time - start_time
    return text_duration

def time_to_int(start_time):
    start_time = start_time.replace(",", "")
    start_time = start_time.replace(":", "")
    start_time = int(start_time) 
    return start_time


# 生成视频实现
def _gen_video_impl(config, jsonObj, callback_url, progress_url):
    print(f"{config}-开始生成视频...")
    print(f"{config}-生成配置：", jsonObj)

    videoCount = jsonObj["videoCount"]
    width = jsonObj["videoSize"]["width"]
    height = jsonObj["videoSize"]["height"]
    videoMinDuration = jsonObj["videoMinSecs"]
    videoMaxDuration = jsonObj["videoMaxSecs"]
    fps = jsonObj["fps"]
    font= jsonObj["fontFamily"]
    outputPath = jsonObj["output"]
    if outputPath=="":
        outputPath="."
    scenes = jsonObj["scenes"]

    genedVideoList = []
    tmp_dir=f"{config}"
    mkdir(tmp_dir)
    tmp_files_dir=os.path.abspath(tmp_dir)+"/"

    # java端已处理数量
    videoCount = 1

    for curVideoIndex in range(videoCount):
        print(f"{config}-正在生成第 {curVideoIndex + 1} 个视频...")
        time.sleep(1)
        # 输出视频时长
        output_duration = random.randint(videoMinDuration, videoMaxDuration)
        print(f"{config}-正在生成第 {curVideoIndex + 1} 个视频, 目标视频时长：{output_duration}s")

        # 暂时只有一个场景
        scene=scenes[0]
        sceneName=scene["name"]
        video_clip_paths=[]
        audio_clips=[]
        voice_clips=[]
        subtitles=[]
        subtitles_font_size= 36
        subtitles_font_family= "FangSong"
        subtitles_font_color= "H00FFFFFF"
        subtitles_font_outline_color= "H00e0611d"

        subtitles_title=[]
        subtitles_title_font_size= 48
        subtitles_title_font_family= "FangSong"
        subtitles_title_font_color= "H00FFFFFF"
        subtitles_title_font_outline_color= "H00e0611d"
        
        subtitles_sub_title=[]
        subtitles_sub_title_font_size= 36
        subtitles_sub_title_font_family= "FangSong"
        subtitles_sub_title_font_color= "H00FFFFFF"
        subtitles_sub_title_font_outline_color= "H00e0611d"

        cover_mp4_path=""
        icon_path=""
        # title_font_size=60
        subtitles_font_size=36

        iconX=10
        iconY=10
        iconW=50
        iconH=50


        # 标题
        if "cover" in scene:
            cover_obj = scene["cover"]
            # 取封面片段
            cover_video_path0 = cover_obj["source"]
            cover_video_path=f"{cover_video_path0}"
            print(f"{config}-正在处理场景封面：{sceneName}-{cover_video_path}")
            cover_start_time_str = cover_obj["coverStartTime"]
            cover_end_time_str = cover_obj["coverEndTime"] 

            source_start_time=time_to_int(cover_start_time_str)
            source_end_time=time_to_int(cover_end_time_str)
            source_duration = source_end_time - source_start_time

            target_duration_str=format_seconds(source_duration)

            # 切割视频
            cover_mp4_path=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_scale_and_sub(cover_video_path,cover_mp4_path,cover_start_time_str,target_duration_str,width,height,False)
            video_clip_paths.insert(0,cover_mp4_path)

            # titleIndex=1
            tmp_title_strs=[]
            tmp_sub_title_strs=[]
            
            # 主标题
            if "caption1" in cover_obj:
                caption1 = cover_obj["caption1"]
                text=caption1["source"]
                text_str=f"{text}"
                text_str=text_str.replace("\n","\\N")

                subtitles_title_font_size= caption1["fontSize"]
                subtitles_title_font_family= caption1["fontFamily"]
                subtitles_title_font_color= caption1["primaryColor"]
                subtitles_title_font_outline_color= caption1["outlineColor"]
                subtitles_title_duration= caption1["duration"]
                title_x= caption1["x"]
                title_y= caption1["y"]

                title_target_duration_str=format_seconds(subtitles_title_duration)

                # tmp_title_strs.append(f"{titleIndex}")
                # titleIndex=titleIndex+1
                # tmp_title_strs.append(f"00:00:00,000 --> {target_duration_str},000")
                # tmp_title_strs.append(f"{text_str}")
                text_str="{\pos("+f"{title_x}"+","+f"{title_y}"+")}"+text_str
                tmp_title_strs.append(f"Dialogue: 0,00:00:00.00,{title_target_duration_str}.00,Default,,0,0,0,,{text_str}")
                tmp_title_strs.append(f"")
            # 副标题
            if "caption2" in cover_obj:
                caption2 = cover_obj["caption2"]
                text=caption2["source"]
                text_str=f"{text}"
                text_str=text_str.replace("\n","\\N")

                subtitles_sub_title_font_size= caption2["fontSize"]
                subtitles_sub_title_font_family= caption2["fontFamily"]
                subtitles_sub_title_font_color= caption2["primaryColor"]
                subtitles_sub_title_font_outline_color= caption2["outlineColor"]
                subtitles_sub_title_duration= caption2["duration"]
                sub_title_x= caption2["x"]
                sub_title_y= caption2["y"]
                
                sub_title_target_duration_str=format_seconds(subtitles_sub_title_duration)

                # tmp_title_strs.append(f"{titleIndex}")
                # titleIndex=titleIndex+1
                # tmp_title_strs.append(f"00:00:00,000 --> {target_duration_str},000")
                # tmp_title_strs.append(f"{text_str}")
                text_str="{\pos("+f"{sub_title_x}"+","+f"{sub_title_y}"+")}"+text_str
                tmp_sub_title_strs.append(f"Dialogue: 0,00:00:00.00,{sub_title_target_duration_str}.00,Default,,0,0,0,,{text_str}")
                tmp_sub_title_strs.append(f"")
            
            subtitles_title.append("\n".join(tmp_title_strs))
            subtitles_sub_title.append("\n".join(tmp_sub_title_strs))

            subtitles_title = [item for item in subtitles_title if item.strip()]
            subtitles_sub_title = [item for item in subtitles_sub_title if item.strip()]

            # 图标
            if "icon" in cover_obj:
                icon = cover_obj["icon"]
                if "source" in icon:
                    imageSource=icon["source"]
                    iconX=icon["x"]
                    iconY=icon["y"]
                    iconW=icon["width"]
                    iconH=icon["height"]
                    icon_path=f"{imageSource}"
        if "sourceList" in scene:
            sourceList = scene["sourceList"]
            for source in sourceList:
                sourceType = source["type"]
                
                print(f"{config}-{sceneName}正在处理素材：{source['source']}")
                if sourceType == "video":
                    # 视频
                    source_path0= source["source"]
                    source_path = f"{source_path0}"
                    source_path=source_path.replace("\\","/")
                    source_path=source_path.replace("//","/")
                    
                    source_start_time_str = source["startTime"]
                    source_duration = source["duration"]
                    source_with_voice = source["voice"]=="1"

                    start_time=time_to_int(source_start_time_str)
                    end_time_str=format_seconds(source_duration)
                    tmp_clip_path=f"{tmp_files_dir}{sceneName}-{uuid_str()}.mp4"

                    ffmpeg_mp4_scale_and_sub(source_path,tmp_clip_path,source_start_time_str,end_time_str,width,height,source_with_voice)
                    video_clip_paths.append(tmp_clip_path)

                if sourceType == "caption":
                    # 字幕
                    text=source["source"]
                    text_str=f"{text}"
                    text_str=text_str.replace("\n","\\N")

                    start_time_str = source["startTime"]
                    source_duration = source["duration"]

                    subtitles_font_size= source["fontSize"]
                    subtitles_font_family= source["fontFamily"]
                    subtitles_font_color= source["primaryColor"]
                    subtitles_font_outline_color= source["outlineColor"]
                    subtitles_x= source["x"]
                    subtitles_y= source["y"]
                    
                    caption_start_time=time_to_int(start_time_str)
                    caption_end_time = caption_start_time + source_duration
                    end_time_str=format_seconds(caption_end_time)

                    # index=len(subtitles)+1
                    tmp_strs=[]
                    # tmp_strs.append(f"{index}")
                    # tmp_strs.append(f"{start_time_str},000 --> {end_time_str},000")
                    # tmp_strs.append(f"{text_str}")
                    text_str="{\pos("+f"{subtitles_x}"+","+f"{subtitles_y}"+")}"+text_str
                    tmp_strs.append(f"Dialogue: 0,{start_time_str}.00,{end_time_str}.00,Default,,0,0,0,,{text_str}")
                    tmp_strs.append(f"")
                    subtitles.append("\n".join(tmp_strs))

                if sourceType == "voice":
                    source_start_time_str = source["sourceStartTime"]
                    source_end_time_str = source["sourceEndTime"]
                    # 什么时候开始播放音频
                    start_time_str = source["startTime"]
                    end_time_str = source["endTime"]

                    start_time=time_to_int(start_time_str)
                    end_time=time_to_int(end_time_str)

                    source_path= source["source"]
                    audioSource = f"{source_path}"
                    audioSource=audioSource.replace("\\","/")
                    audioSource=audioSource.replace("//","/")

                    # 音频持续时间
                    audio_duration=end_time-start_time

                    if audio_duration<=0:
                        print(f"{config}-{sceneName}口播素材时间不足，忽略：{source['source']}")
                        continue
                    
                    audio_path=f"{audioSource}"
                    if audio_path.endswith(".wav"):
                        mp3_path=f"{tmp_files_dir}{uuid_str()}.mp3"
                        if ffmpeg_wav_to_mp3(audio_path,mp3_path)==True:
                            audio_path=mp3_path
                    if file_exist(audio_path)==True:
                        voice_clips.append(audio_path)
                if sourceType == "audio":
                    source_start_time_str = source["sourceStartTime"]
                    source_end_time_str = source["sourceEndTime"]
                    # 什么时候开始播放音频
                    start_time_str = source["startTime"]
                    end_time_str = source["endTime"]
                    
                    source_path= source["source"]
                    audioSource = f"{source_path}"
                    audioSource=audioSource.replace("\\","/")
                    audioSource=audioSource.replace("//","/")

                    start_time=time_to_int(start_time_str)
                    end_time=time_to_int(end_time_str)
                    # 音频持续时间
                    audio_duration=end_time-start_time

                    source_start_time=time_to_int(source_start_time_str)
                    source_end_time=time_to_int(source_end_time_str)

                    sub_duration=source_end_time-source_start_time
                    source_end_str=format_seconds(sub_duration)

                    audio_path=f"{audioSource}"
                    if audio_path.endswith(".wav"):
                        mp3_path=f"{tmp_files_dir}{uuid_str()}.mp3"
                        if ffmpeg_wav_to_mp3(audio_path,mp3_path)==True:
                            audio_path=mp3_path

                    if file_exist(audio_path)==True:
                        mp3_clip_path=f"{tmp_files_dir}{uuid_str()}.mp3"
                        ffmpeg_mp3_sub(audio_path,mp3_clip_path,tmp_files_dir,source_start_time_str,source_end_str,start_time)
                        audio_clips.append(mp3_clip_path)
                print(f"{config}-{sceneName}完成处理素材：{source['source']}")

        # 输出视频文件路径
        file_name = get_time_str()
        output_video_filename = os.path.join(outputPath, f"{file_name}.mp4")
        output_video_filename= output_video_filename.replace("\\","/")
        output_video_filename= output_video_filename.replace("//","/")

       
        # 合并视频
        print("--------------------------------合并所有视频")
        all_mp4=f"{tmp_files_dir}{uuid_str()}.mp4"
        ffmpeg_mp4_concat(all_mp4,tmp_files_dir,video_clip_paths)
        send_post_progress(progress_url, {"id": config, "progress": "10"})
        # 合并音频
        print("--------------------------------合并所有音频")
        all_mp3=f"{tmp_files_dir}{uuid_str()}.mp3"
        all_mp3_generated=ffmpeg_mp3_concat(all_mp3,tmp_files_dir,audio_clips)
        send_post_progress(progress_url, {"id": config, "progress": "20"})
        # 合并声音
        print("--------------------------------合并所有语音")
        all_voice=f"{tmp_files_dir}{uuid_str()}.mp3"
        all_voice_generated=ffmpeg_mp3_concat(all_voice,tmp_files_dir,voice_clips)
        send_post_progress(progress_url, {"id": config, "progress": "30"})

        gen_tmp_path=all_mp4
        # 生成字幕
        print("--------------------------------生成字幕")
        if len(subtitles)>0:
            srt_file_name=f"{uuid_str()}.srt"
            all_subtitles=f"./{srt_file_name}"
            with open(all_subtitles, 'w' , encoding='utf-8') as file:
                file.write(f"""
[Script Info]
; Script generated by your tool
Title: My Movie Subtitles
ScriptType: v4.00+
PlayResX: {width}
PlayResY: {height}

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default, {subtitles_font_family},{subtitles_font_size},&H{subtitles_font_color},&H000000FF,&H{subtitles_font_outline_color},&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
""")

                for line in subtitles:
                    file.write(line + '\n')
            # 给视频添加字幕
            output1=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_subtitles(all_mp4,output1,srt_file_name)
            gen_tmp_path=output1
            delete_file(all_subtitles)
 
        send_post_progress(progress_url, {"id": config, "progress": "40"})

        # 主标题
        print("--------------------------------生成主标题")
        if len(subtitles_title)>0:
            srt_file_name=f"{uuid_str()}.ass"
            all_title_subtitles=f"./{srt_file_name}"
            with open(all_title_subtitles, 'w' , encoding='utf-8') as file:
                file.write(f"""
[Script Info]
; Script generated by your tool
Title: My Movie Subtitles
ScriptType: v4.00+
PlayResX: {width}
PlayResY: {height}

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default, {subtitles_title_font_family},{subtitles_title_font_size},&H{subtitles_title_font_color},&H000000FF,&H{subtitles_title_font_outline_color},&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
""")
                for line in subtitles_title:
                    file.write(line + '\n')
            # 给视频添加标题
            output2=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_subtitles(gen_tmp_path,output2,srt_file_name)
            gen_tmp_path=output2
            delete_file(all_title_subtitles)

        send_post_progress(progress_url, {"id": config, "progress": "45"})

        # 副标题
        print("--------------------------------生成副标题")
        if len(subtitles_sub_title)>0:
            srt_file_name=f"{uuid_str()}.ass"
            all_title_sub_subtitles=f"./{srt_file_name}"
            with open(all_title_sub_subtitles, 'w' , encoding='utf-8') as file:
                file.write(f"""
[Script Info]
; Script generated by your tool
Title: My Movie Subtitles
ScriptType: v4.00+
PlayResX: {width}
PlayResY: {height}

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default, {subtitles_sub_title_font_family},{subtitles_sub_title_font_size},&H{subtitles_sub_title_font_color},&H000000FF,&H{subtitles_sub_title_font_outline_color},&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
""")
                for line in subtitles_sub_title:
                    file.write(line + '\n')
            # 给视频添加标题
            output2=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_subtitles(gen_tmp_path,output2,srt_file_name)
            gen_tmp_path=output2
            delete_file(all_title_sub_subtitles)

        send_post_progress(progress_url, {"id": config, "progress": "50"})
                
        # 给视频加入音乐
        print("--------------------------------背景音乐")
        if all_mp3_generated:
            output3=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_audio(gen_tmp_path,output3,all_mp3)
            gen_tmp_path=output3

        send_post_progress(progress_url, {"id": config, "progress": "60"})

        # 给视频加入人声
        print("--------------------------------人声")
        if all_voice_generated:
            output4= f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_audio(gen_tmp_path,output4,all_voice)
            gen_tmp_path=output4
            
        send_post_progress(progress_url, {"id": config, "progress": "70"})

        # 给视频加入图标
        print("--------------------------------图标")
        if len(icon_path)>0:
            output5=f"{tmp_files_dir}{uuid_str()}.mp4"
            ffmpeg_mp4_add_icon(gen_tmp_path,output5,icon_path,iconW,iconH,iconX,iconY)    
            gen_tmp_path=output5 

        send_post_progress(progress_url, {"id": config, "progress": "80"})

        # 剪裁
        print("--------------------------------剪裁")
        total_end_time=format_seconds(output_duration)
        ffmpeg_mp4_sub(gen_tmp_path,output_video_filename,"00:00:00",total_end_time)
        send_post_progress(progress_url, {"id": config, "progress": "90"})

        # 回调数据
        print("--------------------------------回调")
        if file_exist(output_video_filename)==True:
            genedVideoList.append(output_video_filename)
        print(f"{config}-第 {curVideoIndex + 1} 个视频生成完成.")
        delete_dir(tmp_dir)
        send_post_progress(progress_url, {"id": config, "progress": "99"})

    print(f"{config}-生成视频完成.")
    send_post_progress(progress_url, {"id": config, "progress": "100"})
    # 生成完成，通知调用方
    notifyContent = {"id": config, "genedVideoList": genedVideoList}
    send_post(callback_url, notifyContent)
    print(f"{config}-已发送回调.")

def divide_and_format(a: int, b: int) -> str:
    # 先执行除法操作
    result = a / b
    # 使用 format() 函数将结果格式化为带有最多两位小数的字符串
    formatted_result = format(result, ".2f")
    return formatted_result

def gen_video_impl(config, jsonStr, callback_url, progress_url):
    print(f"{config}-创建生成视频任务...")
    thread = threading.Thread(
        target=_gen_video_impl, args=(config, jsonStr, callback_url, progress_url)
    )  # 创建一个新线程来执行 async_function
    thread.start()  # 启动新线程
    print(f"{config}-已创建生成视频任务")



